﻿namespace HREngine.Bots
{
    using System.Collections.Generic;

    public class Movegenerator
    {
        PenalityManager pen = PenalityManager.Instance;

        private static Movegenerator instance;

        public static Movegenerator Instance
        {
            get
            {
                return instance ?? (instance = new Movegenerator());
            }
        }

        private Movegenerator()
        {
        }
        
        public List<Action> getMoveList(Playfield p, bool usePenalityManager, bool useCutingTargets, bool own) //得到潜在的动作列表,并给每个动作打分
        {
            //generates only own moves
            List<Action> ret = new List<Action>();
            List<Minion> trgts = new List<Minion>();

            if (p.complete || p.ownHero.Hp <= 0)
            {
                return ret;
            }

          //play cards:
            if (own)
            {
                foreach (Handmanager.Handcard hc in p.owncards)
                {
                    //if (hc.card.name == CardDB.cardName.unknown) // 有一些sim比如耶比托·乔巴斯会抽出unknown的卡，会导致后面出异常
                    int cardCost = hc.card.getManaCost(p, hc.manacost);
                    if (p.mana < cardCost) continue; // if not enough manna

                    CardDB.Card c = hc.card;
                    
                        //如果场上随从满了，就无法继续出随从牌了
                        if (p.ownMinions.Count > 6) continue;
                        trgts = c.getTargetsForCard(p, p.isLethalCheck, true);
                        if (trgts.Count == 0) continue;

                        int cardplayPenality = 0;
                        int bestplace = p.getBestPlace(c.type == CardDB.cardtype.MOB ? c : hc.card, p.isLethalCheck);
                        foreach (Minion trgt in trgts)
                        {
                            if (usePenalityManager) cardplayPenality = pen.getPlayCardPenality(c, trgt, p);  //得到打出每张牌的惩罚值
                            if (cardplayPenality <= 499) // 这步可以去掉一些惩罚值过高的动作
                            {
                                Action a = new Action(actionEnum.playcard, hc, null, bestplace, trgt, cardplayPenality, 0);
                                ret.Add(a);
                            }
                        }
                }
            }

            //get targets for Hero weapon and Minions  ###################################################################################
            /*
              trgts = p.getAttackTargets(own, p.isLethalCheck);
              if (!p.isLethalCheck) trgts = this.cutAttackList(trgts);

            // attack with minions
              List<Minion> attackingMinions = new List<Minion>(8);
              foreach (Minion m in (own ? p.ownMinions : p.enemyMinions))
              {
                  if (m.Ready && m.Angr >= 1 && !m.frozen) attackingMinions.Add(m); //* add non-attacing minions
              }
              attackingMinions = this.cutAttackList(attackingMinions);

              foreach (Minion m in attackingMinions)
              {
                  int attackPenality = 0;
                  foreach (Minion trgt in trgts)
                  {
                      if (m.cantAttackHeroes && trgt.isHero) continue;
                      if (usePenalityManager) attackPenality = pen.getAttackWithMininonPenality(m, p, trgt);
                      if (attackPenality <= 499)
                      {
                          Action a = new Action(actionEnum.attackWithMinion, null, m, 0, trgt, attackPenality, 0);
                          ret.Add(a);
                      }
                  }
              }

            // attack with hero (weapon)
              if ((own && p.ownHero.Ready && p.ownHero.Angr >= 1) || (!own && p.enemyHero.Ready && p.enemyHero.Angr >= 1))
              {
                  int heroAttackPen = 0;
                  foreach (Minion trgt in trgts)
                  {
                      if ((own ? p.ownWeapon.cantAttackHeroes : p.enemyWeapon.cantAttackHeroes) && trgt.isHero) continue;
                      if (usePenalityManager) heroAttackPen = pen.getAttackWithHeroPenality(trgt, p);
                      if (heroAttackPen <= 499)
                      {
                          Action a = new Action(actionEnum.attackWithHero, null, (own ? p.ownHero : p.enemyHero), 0, trgt, heroAttackPen, 0);
                          ret.Add(a);
                      }
                  }
              }
              */
            // Buy Minion
            if (p.mana >= 3 && p.owncards.Count < 10)  // Todo: 米尔豪斯
            {
                foreach (Minion m in p.enemyMinions)
                {
                    int buyPenality = 0;
                    buyPenality = 20 - m.Angr - m.Hp;    // Todo: Add Pen
                    if (buyPenality <= 499)
                    {
                        Action a = new Action(actionEnum.buyMinion, null, m, 0, null, buyPenality, 0);
                        ret.Add(a);
                    }
                }
            }

            // Sell Minion
            foreach (Minion m in p.ownMinions)
            {
                int sellPenality = 0;
                sellPenality = 70 - p.ownMinions.Count * 10;    // Todo: Add Pen
                if (sellPenality <= 0 && p.mana >= 2)
                {
                    Action a = new Action(actionEnum.sellMinion, null, m, 0, null, sellPenality, 0);
                    ret.Add(a);
                }
            }

            // Refresh
            if (p.mana >= 1)    // Todo: Dynamic
            {
                Action a = new Action(actionEnum.refresh, null, null, 0, null, 0, 0);
                ret.Add(a);
            }
            // Upgrade
            if (p.mana >= p.upgradeMana && p.techLevel < 6)
            {
                Action a = new Action(actionEnum.upgrade, null, null, 0, null, 0, 0);
                ret.Add(a);
            }
            // Freeze
            if (!p.isFreezing && p.mana == 0)
            {
                Action a = new Action(actionEnum.freeze, null, null, 0, null, 0, 0);
                ret.Add(a);
            }

            // use own ability
            if (false && own)   // Todo: Enable
            {
                if (p.ownAbilityReady && p.mana >= p.ownHeroAblility.card.getManaCost(p, p.ownHeroAblility.manacost)) // if ready and enough manna
                {
                    CardDB.Card c = p.ownHeroAblility.card;
                    if (!c.passive)
                    {
                        int isChoice = (c.choice) ? 1 : 0;
                        for (int choice = 0 + 1 * isChoice; choice < 1 + 2 * isChoice; choice++)
                        {
                            if (isChoice == 1)
                            {
                                c = pen.getChooseCard(p.ownHeroAblility.card, choice); // do all choice
                            }
                            int cardplayPenality = 0;
                            int bestplace = p.ownMinions.Count + 1; //we can not manage it
                            trgts = p.ownHeroAblility.card.getTargetsForHeroPower(p, true);
                            foreach (Minion trgt in trgts)
                            {
                                if (usePenalityManager) cardplayPenality = pen.getPlayCardPenality(p.ownHeroAblility.card, trgt, p);
                                if (cardplayPenality <= 499)
                                {
                                    Action a = new Action(actionEnum.useHeroPower, p.ownHeroAblility, null, bestplace, trgt, cardplayPenality, choice);
                                    ret.Add(a);
                                }
                            }
                        }
                    }
                }
            }

            // End Turn
            if (ret.Count == 0)
            {
                Action a = new Action(actionEnum.endturn, null, null, 0, null, 0, 0);
                ret.Add(a);
            }

            return ret;
        }
        
    }

}